<html>
    <head>
        <title>高级主题</title>
    </head>
    <body>
        <script>
            /*
                        三、高级主题

                                1、IObjectMapper接口

                                            假设你已经创建了一个可重用模块，它定义了AutoMapper配置文件并在需要映射对象时使用IObjectMapper。
                                            
                                            然后，根据模块化的性质，你的模块可以在不同的应用程序中使用。

                                            IObjectMapper是一个抽象，可以被最终应用程序替换以使用另一个映射库。这里的问题是，你的可重用模块被设计为使用AutoMapper库，因为它只为其定义映射。
                                            
                                            在这种情况下，你将希望保证你的模块始终使用AutoMapper，即使最终应用程序使用另一个默认对象映射库。

                                            IObjectMapper<TContext> 用于"上下文化"对象映射，因此你可以为不同的模块/上下文使用不同的映射库：

                                                    eg: 使用方法

                                                        public class UserAppService : ApplicationService
                                                        {
                                                            private readonly IRepository<User, Guid> _userRepository;   
                                                            
                                                            private readonly IObjectMapper<MyModule> _objectMapper;

                                                            public UserAppService(
                                                                IRepository<User, Guid> userRepository, 
                                                                IObjectMapper<MyModule> objectMapper) //Inject module specific mapper
                                                            {
                                                                _userRepository = userRepository;
                                                                _objectMapper = objectMapper;
                                                            }

                                                            public async Task CreateUserAsync(CreateUserInput input)
                                                            {
                                                                //Use the module specific mapper
                                                                var user = _objectMapper.Map<CreateUserInput, User>(input);

                                                                await _userRepository.InsertAsync(user);
                                                            }
                                                        }

                                                    UserAppService注入IObjectMapper<MyModule>，即该模块的特定对象映射器。它的用法与IObjectMapper完全相同。

                                                    上面的示例代码不使用ApplicationService中定义的ObjectMapper属性，而是注入IObjectMapper<MyModule>。

                                                     但是，仍然可以使用基本属性，因为ApplicationService定义了一个可以在类构造函数中设置的ObjectMapperContext属性   

                                                    所以，关于的例子可以重写如下：

                                                            public class UserAppService : ApplicationService
                                                            {
                                                                private readonly IRepository<User, Guid> _userRepository;

                                                                public UserAppService(IRepository<User, Guid> userRepository)
                                                                {
                                                                    _userRepository = userRepository;

                                                                    // 设置映射上下文
                                                                    ObjectMapperContext = typeof(MyModule); // 设置当前服务的映射上下文(使用哪个模块的映射)
                                                                }

                                                                public async Task CreateUserAsync(CreateUserInput input)
                                                                {
                                                                    // 设置当前服务的映射上下文后使用普通映射器
                                                                    var user = ObjectMapper.Map<CreateUserInput, User>(input);

                                                                    await _userRepository.InsertAsync(user);
                                                                }
                                                            }

                                            虽然使用上"下文化对象映射器"与普通对象映射器相同，但你应该在模块的ConfigureServices 方法中注册"上下文化映射器"：、

                                                    [DependsOn(typeof(AbpAutoMapperModule))]
                                                    public class MyModule : AbpModule
                                                    {
                                                        public override void ConfigureServices(ServiceConfigurationContext context)
                                                        {
                                                            // 为MyModule模块使用AutoMapper
                                                            context.Services.AddAutoMapperObjectMapper<MyModule>();

                                                            Configure<AbpAutoMapperOptions>(options =>
                                                            {
                                                                options.AddMaps<MyModule>(validate: true);
                                                            });
                                                        }
                                                    }


                                        IObjectMapper<MyModule>是可重用模块的基本功能，它可以在多个应用程序中使用，每个应用程序都可以使用不同的库进行对象到对象的映射。

                                         所有预构建的ABP模块都在使用它。但是，对于最终的应用程序，你可以忽略此接口并始终使用默认的IObjectMapper接口。   



                            2、IObjectMapper<TSource， TDestination>接口

                                        ABP允许你自定义特定类的映射代码。
                                        
                                        假设你要创建一个自定义类以从User映射到UserDto。在这种情况下，你可以创建一个实现IObjectMapper<User, UserDto>的类：

                                            public class MyCustomUserMapper : IObjectMapper<User, UserDto>, ITransientDependency
                                            {
                                                public UserDto Map(User source)
                                                {
                                                    //TODO: Create a new UserDto
                                                }

                                                public UserDto Map(User source, UserDto destination)
                                                {
                                                    //TODO: 映射到现有Dto对象
                                                    return destination;
                                                }
                                            }

                                        ABP会自动发现并注册MyCustomUserMapper，并且每当你使用IObjectMapper将User映射到UserDto时，它会自动使用。

                                        单个类可以为不同的对象对实现多个IObjectMapper<TSource, TDestination>。

                                        种方法很强大，因为MyCustomUserMapper可以注入任何其他服务并在Map方法中使用。


                                        一旦实现了IObjectMapper<User, UserDto>，ABP就可以自动将User对象的集合转换为UserDto对象的集合:

                                                      IEnumerable<T>

                                                      ICollection<T>

                                                      Collection<T>

                                                      IList<T>

                                                      List<T>

                                                      T[] (array) T[]（数组） 

                                            eg: 
                                                    var users = await _userRepository.GetListAsync(); // returns List<User>
                                                    var dtos = ObjectMapper.Map<List<User>, List<UserDto>>(users); // creates List<UserDto>
                    */
        </script>
    </body>
</html>